package com.yjpark.apps.netcalc;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.KeyguardManager;
import android.app.ProgressDialog;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.text.Editable;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;

import com.yjpark.protocols.*;

public class CalculateActivity extends Activity {

    // sensor
    SensorManager sm;
    SensorEventListener accL;
    SensorEventListener oriL;    
    Sensor oriSensor;
    Sensor accSensor;
       
    float maxAccX;
    float maxAccY;
    float maxAccZ;
    private long lastTime;
    private float speed;
    private float lastX;
    private float lastY;
    private float lastZ;
   
    private float x, y, z;
    private static final int SHAKE_THRESHOLD = 500;
   
    private static final int DATA_X = SensorManager.DATA_X;
    private static final int DATA_Y = SensorManager.DATA_Y;
    private static final int DATA_Z = SensorManager.DATA_Z;
    
    private ListView listViewCalc;//

    private ArrayAdapter<String> mCalcArrayAdapter;

    private EditText editTextCalc;

    private Handler handler = new Handler(); //

    private CalculateNetwork CalculateNetwork;

    Socket socket = UserApplication.getSocket();

    // for intent
    static String id = null;

    static String loginSession = null;

    // for progressbar
    static final int PROGRESS_DIALOG = 0;

    ProgressThread progressThread;

    ProgressDialog progressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.calculate_layout);

        // LoginActivity intent
        Intent intent = getIntent();
        id = intent.getStringExtra("LOGIN_ID");
        loginSession = intent.getStringExtra("LOGIN_SESSION");

        // 로그인 확인 메시지
        if (!id.equals(""))
            Toast.makeText(CalculateActivity.this, "Welcome! " + id,
                    Toast.LENGTH_SHORT).show();

        editTextCalc = (EditText) findViewById(R.id.editTextCalc);

        // imageView click listener
        findViewById(R.id.imageView00).setOnClickListener(mClickListener);
        findViewById(R.id.imageView01).setOnClickListener(mClickListener);
        findViewById(R.id.imageView02).setOnClickListener(mClickListener);
        findViewById(R.id.imageView03).setOnClickListener(mClickListener);
        findViewById(R.id.imageView04).setOnClickListener(mClickListener);
        findViewById(R.id.imageView05).setOnClickListener(mClickListener);
        findViewById(R.id.imageView06).setOnClickListener(mClickListener);
        findViewById(R.id.imageView07).setOnClickListener(mClickListener);
        findViewById(R.id.imageView08).setOnClickListener(mClickListener);
        findViewById(R.id.imageView09).setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_01).setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_02).setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_03).setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_04).setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_05).setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_06).setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_07).setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_08).setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_dot)
                .setOnClickListener(mClickListener);
        findViewById(R.id.imageView_icon_plusminus).setOnClickListener(
                mClickListener);

        listViewCalc = (ListView) findViewById(R.id.listViewCalc);
        mCalcArrayAdapter = new ArrayAdapter<String>(this, R.layout.textstyle);
        listViewCalc.setAdapter(mCalcArrayAdapter);

        handler = new Handler() {
            public void handleMessage(Message msg) {
                Editable CalcStr = editTextCalc.getText();
                String message = (String) msg.obj;

                String[] packetStr = message.split(":");
                String msgType = packetStr[0];
                String msgData = packetStr[1];

                // binary
                if (msgType.equals("M_LOGRES")
                        || msgType.equals("M_PROFILERES")) {

                    // external sdcard 확인
                    String mSdPath;
                    String ext = Environment.getExternalStorageState();
                    if (ext.equals(Environment.MEDIA_MOUNTED)) {
                        mSdPath = Environment.getExternalStorageDirectory()
                                .getAbsolutePath();
                    } else {
                        mSdPath = Environment.MEDIA_UNMOUNTED;
                    }

                    File appPath = new File(mSdPath + "/"
                            + getResources().getString(R.string.app_name));
                    if (!appPath.isDirectory())
                        appPath.mkdirs();

                    String fileName = "log-" + msgType + "-" + id + ".txt";

                    File file = new File(appPath + "/" + fileName);
                    if (!file.exists())
                        mSdPath = "";

                    // 로그 내용 정리
                    // 각 라인별 0-4 로그 헤더 제거
                    byte[] temp = msgData.getBytes();
                    byte[] data = new byte[temp.length];
                    int i = 0;
                    for (int idx = 4; idx < temp.length; idx++) {
                        data[i++] = temp[idx];

                        if (temp[idx] == 10) { // '\n'
                            idx += 4;
                        }
                    }

                    // data <- trim() 구현 필요

                    // 파일 저장
                    FileOutputStream fos = null;
                    try {
                        fos = new FileOutputStream(file);
                        if (fos != null) {
                            fos.write(data);
                        }
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } finally {
                        try {
                            if (fos != null) {
                                fos.close();
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    // 파일 내용 보기
                    showFileDialog(file.toString());

                    // byte[] fileBuffer = new byte[1024];
                    //
                    // FileInputStream inFile;
                    // try {
                    // inFile = new FileInputStream(file);
                    // while(true) {
                    // if(inFile.read(fileBuffer) == -1)
                    // break;
                    // // System.out.write(fileBuffer);
                    // }
                    // inFile.close();
                    // } catch (IOException e1) {
                    // // TODO Auto-generated catch block
                    // e1.printStackTrace();
                    // }
                    //

                } else {
                    // text
                    mCalcArrayAdapter.add(CalcStr.toString() + " = " + msgData);

                    // 입력창 초기화
                    CalcStr.clear();
                }
            }
        };

        // 서버 접속
        CalculateNetwork = new CalculateNetwork(socket, handler);

        // sensor
        sm = (SensorManager)getSystemService(SENSOR_SERVICE);    // SensorManager 인스턴스를 가져옴            
        oriSensor = sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);    // 방향 센서
        accSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);    // 가속도 센서
        oriL = new oriListener();        // 방향 센서 리스너 인스턴스
        accL = new accListener();       // 가속도 센서 리스너 인스턴스
    }

    // ========================================= //
    // sensor

    @Override
    public void onResume() {
        super.onResume();
        sm.registerListener(accL, accSensor, SensorManager.SENSOR_DELAY_NORMAL);    // 가속도 센서 리스너 오브젝트를 등록
        sm.registerListener(oriL, oriSensor, SensorManager.SENSOR_DELAY_NORMAL);    // 방향 센서 리스너 오브젝트를 등록
    }
    
    @Override 
    public void onPause() {
        super.onPause();
        
       sm.unregisterListener(oriL);    // unregister acceleration listener
       sm.unregisterListener(accL);    // unregister orientation listener
    }

    private class accListener implements SensorEventListener {
        public void onSensorChanged(SensorEvent event) {  // 가속도 센서 값이 바뀔때마다 호출됨
            long currentTime = System.currentTimeMillis();
            long gabOfTime = (currentTime - lastTime);
   
            if (gabOfTime > 100) {
                lastTime = currentTime;
   
                x = event.values[SensorManager.DATA_X];
                y = event.values[SensorManager.DATA_Y];
                z = event.values[SensorManager.DATA_Z];
   
                speed = Math.abs(x + y + z - lastX - lastY - lastZ) /
                        gabOfTime * 10000;
   
                System.out.println("speed:"+speed);
                if (speed > SHAKE_THRESHOLD) {
                    
                  // 흔들면 입력창 초기화
                  Editable CalcStr = editTextCalc.getText();
                  CalcStr.clear();
                }
                lastX = event.values[DATA_X];
                lastY = event.values[DATA_Y];
                lastZ = event.values[DATA_Z];
            }
        }
        
        public void onAccuracyChanged(Sensor sensor, int accuracy) {    
        }        
    }
    
    private class oriListener implements SensorEventListener {
        public void onSensorChanged(SensorEvent event) {  // 방향 센서 값이 바뀔때마다 호출됨
            float xVar = event.values[0];
            float yVar = event.values[1];
            float zVar = event.values[2];
            
            float change = maxAccX - xVar;
            
            // 들어올리거나 내리면 계산식 전송
            if( speed < SHAKE_THRESHOLD && ((change > 60 || change < -60)) ) {

                // 입력 값 없을 경우 전송 하지 않는다
                if (editTextCalc.getText().toString().length() > 0) {
                    CalculateNetwork.write(editTextCalc.getText().toString(),
                            "M_CALCREQ");
                    CalculateNetwork.read();
                }
            }
            
//            if (maxAccX < xVar)
                maxAccX = xVar;
//            if (maxAccY < yVar)
                maxAccY = yVar;
//            if (maxAccZ < zVar)
//                maxAccZ = zVar;
            
            System.out.println("xVar:"+xVar);
            System.out.println("yVar"+yVar);
            System.out.println("zVar:"+zVar);
            System.out.println("change:"+change);
            

        }
        
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            
        }
    }

    // ========================================= //

    // 마이너스 표기 관련 변수
    boolean minusFlag = false;

    String minusStr = "";

    // ImageView 에서 클릭하는 리스너 재정의
    ImageView.OnClickListener mClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            String setText = "";
            Editable CalcStr = editTextCalc.getText();

            switch (v.getId()) {
            case R.id.imageView01:
                setText = "1";
                break;
            case R.id.imageView02:
                setText = "2";
                break;
            case R.id.imageView03:
                setText = "3";
                break;
            case R.id.imageView04:
                setText = "4";
                break;
            case R.id.imageView05:
                setText = "5";
                break;
            case R.id.imageView06:
                setText = "6";
                break;
            case R.id.imageView07:
                setText = "7";
                break;
            case R.id.imageView08:
                setText = "8";
                break;
            case R.id.imageView09:
                setText = "9";
                break;
            case R.id.imageView00:
                setText = "0";
                break;
            case R.id.imageView_icon_01:
                setText = "(";
                break;
            case R.id.imageView_icon_02:
                // backspace
                // 입력된 값이 있는 경우만
                if (CalcStr.length() > 0)
                    // 마지막에서 하나씩 지우기
                    CalcStr.delete(CalcStr.length() - 1, CalcStr.length());
                setText = "";
                break;
            case R.id.imageView_icon_03:
                // 입력창 초기화
                CalcStr.clear();
                setText = "";
                break;
            case R.id.imageView_icon_04:
                setText = "/";
                break;
            case R.id.imageView_icon_05:
                setText = "*";
                break;
            case R.id.imageView_icon_06:
                setText = "-";
                break;
            case R.id.imageView_icon_07:
                setText = "+";
                break;
            case R.id.imageView_icon_08:
                // '=' - send
                // 입력된 값이 있는 경우만
                if (CalcStr.length() > 0) {
                    onButtonSend(v);
                }
                break;
            case R.id.imageView_icon_dot:
                // 아무 숫자도 없을 경우에는 "0." 으로 붙여준다.
                if (CalcStr.length() > 0) {
                    setText = ".";
                } else {
                    setText = "0.";
                }
                break;
            case R.id.imageView_icon_plusminus:
                // +/- 전환 처리
                if (minusFlag) {
                    minusStr = "";
                    minusFlag = false;
                } else {
                    minusFlag = true;
                    minusStr = "-";
                }
                break;
            }

            editTextCalc.setText(CalcStr.append(minusStr + "" + setText));
        }
    };

    // "=" 클릭시 네크워크로 수식 전송 처리
    // 프로토콜에 따라 처리
    public void onButtonSend(View v) {
        // 한번 더 예외 처리
        // 입력 값 없을 경우 전송 하지 않는다
        if (editTextCalc.getText().toString().length() > 0) {
            CalculateNetwork.write(editTextCalc.getText().toString(),
                    "M_CALCREQ");
            CalculateNetwork.read();
        }
    }

    // static final private int PROFILE = Menu.FIRST;
    // static final private int ABOUT = Menu.FIRST + 1;
    // static final private int LOG = Menu.FIRST + 2;
    // static final private int LOGOUT = Menu.FIRST + 3;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        boolean result = super.onCreateOptionsMenu(menu);

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.calculate_menu, menu);

        // MenuItem itemProfile = menu.add(0, PROFILE, Menu.NONE,
        // R.string.profile);
        // MenuItem itemAbout = menu.add(0, PROFILE, Menu.NONE, R.string.about);
        // MenuItem itemLog = menu.add(0, PROFILE, Menu.NONE, R.string.log);
        // MenuItem itemLogout = menu.add(0, PROFILE, Menu.NONE,
        // R.string.logout);

        return result;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // TODO Auto-generated method stub
        super.onOptionsItemSelected(item);

        switch (item.getItemId()) {
        case R.id.profile: // profile
            // 프로필 수정 activity 호출
            // CalculateNetwork.write("", "M_LOGREQ");
            return true;
            // case R.id.about: // about
            // return true;
        case R.id.log: // log

            // 로그 요청
            // showDialog(PROGRESS_DIALOG);

            CalculateNetwork.write("data", "M_LOGREQ");
            CalculateNetwork.read();

            // 안내 메세지를 토스트로 출력한다.
            Toast.makeText(this, "로그파일을 수신하였습니다.", Toast.LENGTH_LONG).show();

            return true;
        case R.id.exit: // exit

            // 확인 창
            AlertDialog.Builder ad = new AlertDialog.Builder(
                    CalculateActivity.this);
            ad.setIcon(android.R.drawable.ic_dialog_alert);
            ad.setTitle("Exit");
            ad.setMessage("Do you want to Exit");
            ad.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // 접속 종료
                    CalculateNetwork.write("Bye", "M_BYE");

                    // 프로그램 종료
                    finish();
                }
            }).setNegativeButton("No", null);
            ad.show();

            return true;
        }
        return false;
    }

    // ========================================== //
    // back key double click
    // Back의 상태값을 저장하기 위한 변수
    boolean m_close_flag = false;

    // 일정 시간 후 상태값을 초기화하기 위한 핸들러
    Handler m_close_handler = new Handler() {
        public void handleMessage(Message msg) {
            m_close_flag = false;
        }
    };

    // Back 키가 터치되면 호출되는 메소드
    public void onBackPressed() {
        // m_close_flag 가 false 이면 첫번째로 키가 눌린 것이다.
        if (m_close_flag == false) { // Back 키가 첫번째로 눌린 경우

            // 안내 메세지를 토스트로 출력한다.
            Toast.makeText(this, "취소키를 한번 더 누르시면 종료됩니다.", Toast.LENGTH_LONG)
                    .show();

            // 상태값 변경
            m_close_flag = true;

            // 핸들러를 이용하여 3초 후에 0번 메세지를 전송하도록 설정한다.
            m_close_handler.sendEmptyMessageDelayed(0, 3000);

        } else { // Back 키가 3초 내에 연달아서 두번 눌린 경우

            // 접속 종료
            CalculateNetwork.write("Bye", "M_BYE");

            // 프로그램 종료
            finish();
        }
    }

    protected void onStop() {

        super.onStop();

        // 핸들러에 등록된 0번 메세지를 모두 지운다.
        this.m_close_handler.removeMessages(0);
    }

    // ========================================== //

    // ========================================== //
    // dialog 관련
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case PROGRESS_DIALOG:
            progressDialog = new ProgressDialog(CalculateActivity.this);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.setMessage("Loading...");
            progressThread = new ProgressThread(pghandler);
            progressThread.start();

            return progressDialog;
        default:
            return null;
        }
    }

    // 핸들러는 정의하여 스레드가 메시지를 보내면 프로그레스를 업데이트 합니다.
    final Handler pghandler = new Handler() {
        public void handleMessage(Message msg) {
            int total = msg.getData().getInt("total");

            progressDialog.setProgress(total);
            if (total >= 100) {
                dismissDialog(PROGRESS_DIALOG);
                progressThread.setState(ProgressThread.STATE_DONE);
            }
        }
    };

    @Override
    protected void onPrepareDialog(int id, Dialog dialog) {
        // TODO Auto-generated method stub
        if (id == 1) {
            progressThread = new ProgressThread(handler);
            progressThread.start();
        }
    }

    /** 프로그레스를 처리하는 클래스를 내부 클래스로 정의. */
    private class ProgressThread extends Thread {
        Handler mHandler;

        final static int STATE_DONE = 0;

        final static int STATE_RUNNING = 1;

        int mState;

        int total;

        ProgressThread(Handler h) {
            mHandler = h;
        }

        public void run() {
            mState = STATE_RUNNING;
            total = 0;
            while (mState == STATE_RUNNING) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // 에러처리
                }
                Message msg = mHandler.obtainMessage();
                Bundle b = new Bundle();
                b.putInt("total", total);
                msg.setData(b);
                mHandler.sendMessage(msg);
                total++;
            }
        }

        // 현재의 상태를 설정하는 메소드
        public void setState(int state) {
            mState = state;
        }
    }

    // ========================================== //

    // ========================================== //
    // 파일 내용보기
    public void showFileDialog(String file) {
        AlertDialog.Builder builder = new AlertDialog.Builder(
                CalculateActivity.this);
        try {
            builder.setMessage(readFile(file))
                    .setCancelable(true)
                    .setPositiveButton("Okay",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int id) {
                                    dialog.cancel();
                                }
                            }).show();
        } catch (IOException e) {
            Toast.makeText(CalculateActivity.this, "Error", Toast.LENGTH_SHORT)
                    .show();
            e.printStackTrace();
        }
    }

    public static String readFile(String path) throws IOException {
        FileInputStream stream = new FileInputStream(new File(path));
        try {
            FileChannel fc = stream.getChannel();
            MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0,
                    fc.size());
            return Charset.defaultCharset().decode(bb).toString();
        } finally {
            stream.close();
        }
    }
    // ========================================== //
}
